
/**
 * 虚拟DOM元素的类, 构建实例对象, 用来描述dom
 * type: 指定元素的标签类型，如'li', 'div', 'a'等
 * props: 表示指定元素身上的属性，如class, style, 自定义属性等
 * children: 表示指定元素是否有子节点，参数以数组的形式传入
 */
class Element {
  constructor(type, props, children) {
    this.type = type
    this.props = props
    this.children = children
  }
}

// 创建虚拟dom, 返回虚拟节点(object)
function createElement(type, props, children) {
  return new Element(type, props, children)
}

// render 方法可以将虚拟dom转成真实dom
function render(domObj) {
  // 根据type类型来创建对应的元素
  let el = document.createElement(domObj.type)

  // 再去遍历props属性对象，然后给创建的元素el设置属性
  for (let key in domObj.props) {
    // 设置属性的方法
    setAttr(el, key, domObj.props[key])
  }

  // 遍历子节点
  // 如果是虚拟dom，就继续递归渲染
  // 不是就代表是文本节点，直接创建
  domObj.children.forEach(child => {
    child = (child instanceof Element) ? render(child) : document.createTextNode(child)
    // 添加到对应元素内
    el.appendChild(child)
  })

  return el
}

// 设置属性
function setAttr(node, key, value) {
  switch (key) {
    case 'value':
      // node 是一个 input 或者 textarea 就直接设置其value即可
      if (node.tagName.toLowerCase() === 'input' || node.tagName.toLowerCase() === 'textarea') {
        node.value = value
      } else {
        node.setAttribute(key, value)
      }
      break
    case 'style':
      // 直接赋值行内样式
      node.style.cssText = value
      break
    default:
      node.setAttribute(key, value)
      break
  }
}

// 将元素插入到页面
function renderDom(el, target) {
  target.appendChild(el)
}

export {
  Element,
  createElement,
  render,
  setAttr,
  renderDom
}
